class QuestionnairesController < ApplicationController
  before_filter :login_required
  before_filter :question_pool_required
  
  helper_method :is_selected_answer
  
  def index
    question_pool = session[:current_question_pool]
    @question_pool_name = question_pool.name
    @questionnaires = Questionnaire.find :all
    @questionnaires = @questionnaires.select {|questionnaire| questionnaire.categories.include?(question_pool)}
  end
  
  def new
    question_pool = session[:current_question_pool]
    @questionnaire = Questionnaire.new
    @root_categories = question_pool.children
    @questions = Question.find :all
    @questions = @questions.select {|question| question.categories.include?(question_pool)}
  end
  
  def create
    params[:questionnaire][:max_time] = params[:questionnaire][:hours].to_i.hours + params[:questionnaire][:minutes].to_i.minutes
    params[:questionnaire].delete(:hours); params[:questionnaire].delete(:minutes)
    @questionnaire = Questionnaire.new params[:questionnaire]
    @questionnaire.creator_id = current_user
    initial_categories = @questionnaire.categories
    initial_categories.each do |cat| @questionnaire.categories |= cat.ancestors end
    @questionnaire.categories |= [ session[:current_question_pool] ] # in case no categories have been selected
    if @questionnaire.save
      flash[:notice] = 'Questionnaire successfully added'
      redirect_to questionnaires_path
    else
      render :action => 'new'
    end
  end
  
  def edit
    @questionnaire = Questionnaire.find params[:id]
    @max_hours = @questionnaire.max_time / 3600;
    @max_minutes = (@questionnaire.max_time - @max_hours * 3600) / 60;
    question_pool = session[:current_question_pool]
    @root_categories = question_pool.children
    @questions = Question.find :all
    @questions = @questions.select {|question| question.categories.include?(question_pool)}
  end
  
  def update
    params[:questionnaire][:max_time] = params[:questionnaire][:hours].to_i.hours + params[:questionnaire][:minutes].to_i.minutes
    params[:questionnaire].delete(:hours); params[:questionnaire].delete(:minutes)
    @questionnaire = Questionnaire.find params[:id]
    if @questionnaire.update_attributes(params[:questionnaire])
      @questionnaire.included_questions.map! do |included_question|
        included_question.weight = 1.0 # Will be set in the view when the new control to select&design questions is done
        included_question.save
      end
      ## TBD: It'd better before udpate
      initial_categories = @questionnaire.categories 
      initial_categories.each do |cat| @questionnaire.categories |= cat.ancestors end
      @questionnaire.categories |= [ session[:current_question_pool] ]
      flash[:notice] = 'Questionnaire was successfully updated'
      redirect_to :action => 'show', :id => @questionnaire
    else
      render :action => 'edit'
    end
  end
  
  def show
    @questionnaire = Questionnaire.find params[:id]
    @questionnaire_categories = @questionnaire.categories - [ session[:current_question_pool] ]
    max_time = @questionnaire.max_time;
    @max_hours = max_time / 3600;
    max_time -= @max_hours * 3600;
    @max_minutes = max_time / 60;
  end
  
  def take
    @questionnaire = Questionnaire.find params[:id]
    max_time = @remainingTime = @questionnaire.max_time
    @max_hours = max_time / 3600;
    max_time -= @max_hours * 3600;
    @max_minutes = max_time / 60;
  end
  
  def correct
    @questionnaire        = Questionnaire.find params[:id]
    @corrections          = {}
    @questionnaire_score  = 0
    maximum_score         = 0
    answered_questions    = 0
    correct_answers       = 0
    not_perfect_answers   = 0

    @questionnaire.included_questions.each do |included_question|
      question = included_question.question
      question_score = 0; answered_question = false
      number_of_answers = 0
      @corrections[question] = {}
      if params.key?(:answers) and params[:answers].key?(question.id.to_s)    # Question answered
        answered_question = true
        if (question.kind == 'Selection')
          question.answers.each do |answer|
            number_of_answers += 1
            if answer.order == params[:answers][question.id.to_s].to_i 
              question_score += answer.score
              if (answer.score == 1.0)
                @corrections[question].clear # in case there is more than one correct answer (allowed?)
                @corrections[question][answer] = 'selected_and_right'
              elsif (answer.score > 0.0)
                @corrections[question][answer] = 'selected_and_not_perfect'
              else
                @corrections[question][answer] = 'selected_and_wrong'
              end
            elsif (answer.score == 1.0 && question_score < 1.0)
              @corrections[question][answer] = 'unselected_and_right'
            end
          end
        elsif (question.kind == 'Multi-selection')
          question.answers.each do |answer|
            number_of_answers += 1 if answer.score <= 0
            selected = false
            params[:answers][question.id.to_s].each do |user_answer, nothing|
              if (answer.order == user_answer.to_i)
                selected = true
                question_score += answer.score
                if (answer.score > 0)
                  @corrections[question][answer] = 'selected_and_right'
                elsif (answer.score <= 0)
                  @corrections[question][answer] = 'selected_and_wrong'
                end
                break
              end
            end
            if (!selected and answer.score > 0)
              @corrections[question][answer] = 'unselected_and_right'
            end
          end
        elsif (question.kind == 'Textual')
          question.answers.each do |answer|
            if answer.text == params[:answers][question.id.to_s] 
              question_score += answer.score
              break
            end
          end
        end
      end
      # Apply penalties
      if answered_question
        if question.kind == 'Multi-selection' and @questionnaire.wrong_answer_penalty == -1
          # The final SCORE should be 0 when every answer is ticked
          @corrections[question].each do |answer, result|  
            if result == 'selected_and_wrong'
              question_score -= 1 / number_of_answers # number_of_answers = total number of wrong answers (ticked or not)
            end
          end
        end
        if question.kind == 'Selection' and question_score == 0.0
          if @questionnaire.wrong_answer_penalty == -1
            # the final SCORE should be 0 in average when answered randomly
            question_score = -1.0 / number_of_answers
          else
            question_score = - @questionnaire.wrong_answer_penalty
          end
        end
      else # unanswered question
        question_score = - @questionnaire.no_answer_penalty
      end

      # Store the results for questions and included_questions
      included_question.times_asked += 1
      question.times_asked += 1
      if answered_question
        included_question.times_answered += 1
        question.times_answered += 1
        answered_questions += 1
        if question_score == 1.0
          included_question.correct_answers += 1
          question.correct_answers += 1
          correct_answers += 1
        elsif question_score > 0.0
          not_perfect_answers += 1
          included_question.not_perfect_answers += 1
          question.not_perfect_answers += 1
        end
      end
      maximum_score += included_question.weight
      @questionnaire_score += question_score * included_question.weight
      if (not question.save or not included_question.save)
      
      end
    end
    
    @questionnaire_score /= maximum_score
    # Store statistics for the evaluation (user x questionnaire)
    evaluation = Evaluation.new 
    evaluation.user_id              = current_user
    evaluation.questionnaire_id     = @questionnaire.id
    evaluation.score                = @questionnaire_score
    evaluation.number_of_questions  = @questionnaire.included_questions.length
    evaluation.answered_questions   = answered_questions
    evaluation.correct_answers      = correct_answers
    evaluation.not_perfect_answers  = not_perfect_answers
    # Store statistics for the questionnaire
    score = @questionnaire.average_score * @questionnaire.times_taken
    @questionnaire.times_taken += 1
    score = (score + @questionnaire_score) / @questionnaire.times_taken
    @questionnaire.average_score = score
    # Store statistics for the user
    score = current_user.average_score * current_user.taken_questionnaires
    current_user.taken_questionnaires += 1
    score = (score + @questionnaire_score) / current_user.taken_questionnaires 
    current_user.average_score = score
    
    current_user.answered_questions   += answered_questions
    current_user.unanswered_questions += @questionnaire.included_questions.length - answered_questions
    current_user.correct_answers      += correct_answers
    current_user.not_perfect_answers  += not_perfect_answers
    
    if evaluation.save and @questionnaire.save and current_user.save
      flash[:notice] = 'Evaluation successfully saved' #----- aaaaaa- -- ---
    else
      flash[:notice] = 'Evaluation was not successfully saved'
    end
  end
  
  def destroy
    @questionnaire = Questionnaire.find params[:id]
    IncludedQuestion.destroy_all({:question_id => @questionnaire.questions, :questionnaire_id => self.id})
    @questionnaire.destroy
    redirect_to questionnaires_path
  end
  
  #private
  def is_selected_answer(answer_tag)
    answer_tag.include?("selected") and !answer_tag.include?("unselected")
  end
end
